#include <modules\graphics\opengl\opengl_font.h>

namespace DelGE
{
	namespace Modules
	{
		namespace Graphics
		{
			OpenGLFont::OpenGLFont(string sFilepath, int iSize)
			{
				// Code based upon tutorial @ http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/
				this->pTextures = new GLuint[128];

				this->iSize = iSize;

				FT_Library library;
				FT_Init_FreeType(&library);

				FT_Face face;

				FT_New_Face(library, sFilepath.c_str(), 0, &face);

				FT_Set_Char_Size(face, iSize << 6, iSize << 6, 96, 96);

				glGenTextures(128, this->pTextures);

				for (unsigned char cCharacter = 0; cCharacter < 128; cCharacter ++)
				{
					FT_Load_Glyph(face, FT_Get_Char_Index(face, cCharacter), FT_LOAD_RENDER);

					FT_Glyph glyph;
					FT_Get_Glyph(face->glyph, &glyph);

					FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
					FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

					FT_Bitmap &bitmap = bitmap_glyph->bitmap;

					int width = MathHelper::NextPowerOf2(bitmap.width);
					int height = MathHelper::NextPowerOf2(bitmap.rows);

					// Just like a texture, we need to calculate offsets for the endUVs
					this->pfCharacterUV[cCharacter][0] = (float)bitmap.width / width;
					this->pfCharacterUV[cCharacter][1] = (float)bitmap.rows / height;

					this->piBitmapSize[cCharacter][0] = bitmap.width;
					this->piBitmapSize[cCharacter][1] = bitmap.rows;

					this->piCharacterSize[cCharacter][0] = (face->glyph->advance.x >> 6); // bitwise 
					this->piCharacterSize[cCharacter][1] = (face->glyph->advance.y >> 6);

					this->pfCharacterOffset[cCharacter][0] = (float)bitmap_glyph->left;
					this->pfCharacterOffset[cCharacter][1] = (float)bitmap_glyph->top;

					GLubyte *pCharacterData = new GLubyte[2 * width * height];

					for (int j = 0; j < height; j ++)
					{
						for (int i = 0; i < width; i ++)
						{
								pCharacterData[2 * (i + j * width) + 0] = 
								pCharacterData[2 * (i + j * width) + 1] = 
								(i >= bitmap.width || j >= bitmap.rows) ? 
								0 : bitmap.buffer[i + bitmap.width * j];
						}
					}

					FT_Done_Glyph(glyph);

					glBindTexture(GL_TEXTURE_2D, this->pTextures[cCharacter]);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

					glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pCharacterData);

					delete [] pCharacterData;
				}

				FT_Done_Face(face);
				FT_Done_FreeType(library);
			}

			OpenGLFont::~OpenGLFont()
			{
				glDeleteTextures(DELGE_GRAPHICS_FONT_CHARACTERCOUNT, this->pTextures);
				delete [] this->pTextures;
			}

			GLuint OpenGLFont::GetOpenGLTexture(char cCharacter)
			{
				return this->pTextures[cCharacter];
			}
		}
	}
}